Skip to content

refactor: tags, presets and custom themes read through plain getters (U5) (@miodec) - #8564

Open
Miodec wants to merge 9 commits into
masterfrom
u5-collection-getters
Open

Miodec wants to merge 9 commits into
masterfrom
u5-collection-getters

Conversation

@Miodec

@Miodec Miodec commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

Roadmap step U5: tags, presets and custom themes get the one-getter read pattern.

Summary

Each collection module owns a module-level live query and exports plain getters. They are reactive in components and effects, synchronous everywhere else, never suspend, and return only what's loaded.

 collections/tags.ts            (same shape: presets.ts, custom-themes.ts)
-  useTagsLiveQuery()           # suspending hook, components only
-  useActiveTagsLiveQuery()
-  __nonReactive.getTags()      # escape hatch for plain code
+  createSessionDownload(...)   # this sign-in's download: loading | loaded | failed
+  tagsQuery = createRoot(() => useLiveQuery(... only once status is "loaded"))
+  getTags() / getTag(id) / getActiveTags()   # read tagsQuery.state, never tagsQuery()
+  getTagsStatus()
 collections/utils/
+  session-download.ts
  • Single-row getters are fine-grained. getTag(id) reruns only when that row changes.
  • Loading state uses a status, not Suspense. The settings custom themes list switches on getCustomThemesStatus(): a loading circle, the list, or "Failed to load custom themes" with a Retry button (reloadCustomThemes()).
  • Callers moved to the getters:
    • commandline tag, preset and custom theme lists (they still rebuild on open);
    • the custom-themes check in config metadata;
    • the theme and preset controllers and the preset modals;
    • the settings, account, result and test-notice components;
    • results.ts.
  • __nonReactive is removed from presets and custom themes. Tags keep it for test-logic and result-pb, which move in T6a/T6c.

Fixed along the way

A collection's rows outlive sign-out: the ["user"] query reset doesn't clear them. On the next sign-in the previous session's rows showed as loaded, and the blocking wait for tags and presets returned straight away with them.

 on sign in
-  collection still "ready" with the previous session's rows
+  createSessionDownload: status "loading", start the download
+  getters return nothing, waitForTagsReady/waitForPresetsReady hold
+  query succeeds → "loaded" (rows already written) | fails → "failed" (the wait still returns)

Evidence

  • Before: sign in as A, sign out, sign in as B → getTags() immediately returns A's tags, reported as loaded.
    After: tags.spec "drops the previous user's tags on sign out" passes (fails on the first commit). The same holds for custom themes.
  • Before: a failed custom themes download → the settings list shows the loading circle forever.
    After: "reports a failed download, and loads on reload" passes. In the browser (failure forced): the error and Retry show, and Retry brings in the 20 themes.
  • Getter specs for all three collections cover:
    • sorted rows;
    • a synchronous read right after a write;
    • effects rerunning, but only for their own row;
    • empty and "loading" while signed out;
    • no GC after 10 minutes.
  • Full suite: 1772 passed, and lint is clean. One earlier run had an app-shell routing test fail once; it passed on its own and in later full runs.
  • Browser:
    • The commandline tag, preset and custom theme lists show.
    • Toggling a tag updates the notice above the test.
    • The settings lists refill after signing out and back in.
    • Each sign-in fetches users, custom themes and presets once each, with no duplicates.
    • The console stays clean.

Merge Danger

Door: two-way

Frontend-only refactor and fixes: no API, storage or schema changes.

Blast Radius: moderate

These three collections are read from many places: the commandline, settings, account, the result screen, the test notice, the theme controller and the preset controller. Possible problems:

  • the custom themes list could show a loading state where it used to be briefly empty;
  • sign-in now waits for this session's tags and presets download, not just the first one.

Spec updated in this PR: Server data, Intended deviations ("From user data (U5)") and Q28.

🤖 Generated with Claude Code

Miodec and others added 5 commits November 10, 2026 12:15
…(U5) (@Miodec)

Each collection module owns a module-level live query (in a root that
lives as long as the page) and exports plain getters reading its
`.state`: reactive in components and effects, synchronous elsewhere,
never suspending, returning only what's loaded. Single-row getters
track only their row. A loaded status (`areTagsLoaded`,
`arePresetsLoaded`, `areCustomThemesLoaded`) replaces Suspense for
loading states; the settings custom themes list shows a loading circle
until they load.

Replaces the live-query hooks and the non-test `__nonReactive` callers
(commandline lists, config metadata, theme and preset controllers,
preset modals). `__nonReactive` is gone from presets and custom themes;
tags keep it for the test-page callers until T6a/T6c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he new ones load (@Miodec)

A collection keeps its rows and ready status after sign out (the
["user"] query reset only sets the query back to pending), so the next
sign in briefly saw the previous session's rows reported as loaded, and
the blocking sign-in wait for tags and presets returned at once.

trackLoadSinceSignIn follows each query since the current sign in and
starts its download (replacing the custom themes refetch effect): the
getters' live query and the loaded status wait for it, and so do
waitForTagsReady/waitForPresetsReady (until it settles, so a failed
download doesn't hang sign in).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
)

Since the getters wait for the download since sign in, a failed custom
themes download left the settings list on its loading circle for the
session. The download tracking now reports failure and can retry;
settings shows "Failed to load custom themes" with a retry button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d/failed booleans (@Miodec)

trackLoadSinceSignIn becomes createSessionDownload, with one status
(loading, loaded or failed) and reload(), matching the spec's user-data
load state and reloadUserData(). The collections export getTagsStatus,
getPresetsStatus, getCustomThemesStatus and reloadCustomThemes in place
of areXLoaded, haveCustomThemesFailed and retryCustomThemes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 10, 2026 12:03
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@monkeytypegeorge monkeytypegeorge added frontend User interface or web stuff docs Related to Markdown files and documentation labels Nov 10, 2026
@github-actions github-actions Bot added the waiting for review Pull requests that require a review before continuing label Nov 10, 2026
Miodec and others added 3 commits November 10, 2026 13:05
… session download status (U5)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…notes to one line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Copilot was unable to complete this review at the selected tier due to model policy or plan restrictions.

🟡 Changes recommended

Open review findings indicate unresolved state-handling and performance issues, including missing load-status checks that can bypass the theme limit and a render-time inefficiency from repeated tag sorting.

3 open issues
What changed in this PR

Refactors the tags, presets, and custom themes collections to a non-suspending “plain getter” read pattern backed by a module-level reactive mirror, with per-session download status to avoid leaking previous-session rows across sign-in/out.

Changes:

  • Add session-scoped download/status tracking for user collections (loading/loaded/failed) with reload support.
  • Replace use*LiveQuery()/most __nonReactive reads with synchronous getters (get*, get*Status) across UI, controllers, and commandline.
  • Update collections, components, and tests to validate new getter semantics, session isolation, and failure/retry behavior.
File Description
frontend/​src/​ts/​queries/​index.ts Updates query/reset documentation and wiring to support session-gated collection reads after sign-in/out.
frontend/​src/​ts/​db.ts Removes now-unneeded imports/usages tied to the prior non-reactive tags access pattern.
frontend/​src/​ts/​controllers/​theme-controller.ts Switches theme selection logic to read custom themes via the new getter-based APIs.
frontend/​src/​ts/​controllers/​preset-controller.ts Refactors preset lookup/application to use getPreset() rather than legacy non-reactive access.
frontend/​src/​ts/​config/​metadata.tsx Updates config metadata validation to use custom theme getters for random/custom theme constraints.
frontend/​src/​ts/​components/​pages/​test/​result/​ResultSecondaryStats.tsx Replaces tags live-query reads with synchronous tag getters when rendering secondary stats.
frontend/​src/​ts/​components/​pages/​test/​result/​ResultChart.tsx Updates chart tag labeling to use getTag() without suspending component rendering.
frontend/​src/​ts/​components/​pages/​test/​modes-notice/​TestModesNotice.tsx Migrates active-tag rendering logic from live-query hooks to getActiveTags().
frontend/​src/​ts/​components/​pages/​settings/​custom-setting/​Theme.tsx Reworks custom theme settings UI to use status-driven loading/failed/loaded states with retry and getter reads.
frontend/​src/​ts/​components/​pages/​settings/​custom-setting/​Tags.tsx Moves settings tags list to the new tags getters instead of suspending live queries.
frontend/​src/​ts/​components/​pages/​settings/​custom-setting/​Presets.tsx Moves settings presets list to the new presets getters instead of suspending live queries.
frontend/​src/​ts/​components/​pages/​account/​Table.tsx Refactors account table tag usage to read from tag getters.
frontend/​src/​ts/​components/​pages/​account/​Filters.tsx Updates account filters to source tag data from synchronous getters.
frontend/​src/​ts/​components/​pages/​account/​Charts.tsx Updates account charts/filter summaries to use tag getters.
frontend/​src/​ts/​components/​modals/​preset/​preset-modal-utils.ts Updates preset modal utilities to read active tags through the getter API.
frontend/​src/​ts/​components/​modals/​preset/​EditPresetModal.tsx Migrates the preset edit modal to fetch the edited preset via getPreset().
frontend/​src/​ts/​components/​modals/​EditResultTagsModal.tsx Updates the result tag editor modal to list and resolve tags via getTags().
frontend/​src/​ts/​components/​layout/​footer/​ThemeIndicator.tsx Switches the footer theme indicator to use custom theme getters for availability checks.
frontend/​src/​ts/​commandline/​lists/​tags.ts Refactors commandline tag list generation to use tag getters instead of non-reactive reads.
frontend/​src/​ts/​commandline/​lists/​presets.ts Refactors commandline preset list generation to use presets getters instead of non-reactive reads.
frontend/​src/​ts/​commandline/​lists/​custom-themes-list.ts Refactors commandline custom theme list generation to use custom theme getters instead of non-reactive reads.
frontend/​src/​ts/​collections/​utils/​session-download.ts Introduces a reusable helper to track per-session download lifecycle and expose status/reload/wait semantics.
frontend/​src/​ts/​collections/​tags.ts Implements session-gated tags live-query mirroring with synchronous getters (including single-row access).
frontend/​src/​ts/​collections/​results.ts Updates results collection logic to use active-tag getters where tag data is needed for queries/filters.
frontend/​src/​ts/​collections/​presets.ts Implements session-gated presets mirroring with synchronous getters and removes the prior non-reactive escape hatch.
frontend/​src/​ts/​collections/​custom-themes.ts Implements session-gated custom themes mirroring with synchronous getters, status exposure, and explicit reload support.
frontend/​src/​ts/​auth.tsx Adjusts sign-in flow expectations to align with per-session tags/presets download readiness semantics.
frontend/​__tests__/​controllers/​preset-controller.spec.ts Updates controller tests to mock/spy on the new getter-based preset access pattern.
frontend/​__tests__/​components/​pages/​test/​result/​ResultChart.spec.tsx Updates chart tests to reflect getter-based tag lookup without Suspense-driven behavior.
frontend/​__tests__/​collections/​tags.spec.ts Adds coverage for tags getter semantics, session isolation across sign-out, and status transitions.
frontend/​__tests__/​collections/​presets.spec.ts Adds coverage for presets getter semantics, synchronous reads after writes, and session isolation behavior.
frontend/​__tests__/​collections/​custom-themes.spec.ts Adds coverage for custom themes status, failure/retry behavior, and hiding prior-session rows until loaded.
docs/​specs/​solid-monkeytype/​roadmap.md Marks roadmap step U5 as complete and documents the getter-based collection read approach.

Review effort: Balanced

import { JSXElement, Show } from "solid-js";

import { useCustomThemesLiveQuery } from "../../../collections/custom-themes";
import { getCustomThemes } from "../../../collections/custom-themes";
Comment on lines +215 to 218
if (getCustomThemes().length >= 20) {
showNoticeNotification("Custom themes limit reached");
return;
}
Comment on lines +383 to 387
when={getActiveTags().length > 0}
icon={getActiveTags().length === 1 ? "fa-tag" : "fa-tags"}
openCommandline="tags"
text={tags()
text={getActiveTags()
.map((tag) => tag.name)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Related to Markdown files and documentation frontend User interface or web stuff waiting for review Pull requests that require a review before continuing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants